package pr.lanmu.config.util;

import lombok.SneakyThrows;

import java.text.SimpleDateFormat;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.util.*;

/**
 * 日期转换工具类
 */
public class DateUtil {

    public static Date asDate(LocalDate localDate) {
        return Date.from(localDate.atStartOfDay()
                .atZone(ZoneId.systemDefault())
                .toInstant());
    }

    public static Date asDate(LocalDateTime localDateTime) {
        return Date.from(localDateTime.atZone(ZoneId.systemDefault())
                .toInstant());
    }

    public static LocalDate asLocalDate(Date date) {
        return Instant.ofEpochMilli(date.getTime())
                .atZone(ZoneId.systemDefault())
                .toLocalDate();
    }

    public static LocalDateTime asLocalDateTime(Date date) {
        return Instant.ofEpochMilli(date.getTime())
                .atZone(ZoneId.systemDefault())
                .toLocalDateTime();
    }

    public static LocalDate asLocalDate(Long time) {
        return Instant.ofEpochMilli(time)
                .atZone(ZoneId.systemDefault())
                .toLocalDate();
    }

    public static LocalDateTime asLocalDateTime(Long time) {
        return Instant.ofEpochMilli(time)
                .atZone(ZoneId.systemDefault())
                .toLocalDateTime();
    }

    public static LocalDate asLocalDate(String time) {
        return LocalDate.parse(time, DateTimeFormatter.ofPattern("yyyy-MM-dd"));
    }

    public static LocalDateTime asLocalDateTime(String time) {
        return LocalDateTime.parse(time, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
    }

    public static String formatToLocalDateTime(Long time) {
        return formatToLocalDateTime(asLocalDateTime(time));
    }

    public static String formatToLocalDate(Long time) {
        return formatToLocalDate(asLocalDateTime(time));
    }

    public static String formatToLocalDateTime(LocalDateTime time) {
        return time.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
    }

    public static String format(LocalDateTime time, String format) {
        return time.format(DateTimeFormatter.ofPattern(format));
    }

    public static String formatToLocalDate(LocalDateTime time) {
        return time.format(DateTimeFormatter.ISO_LOCAL_DATE);
    }

    public static String formatToLocalDate(LocalDate time) {
        return time.format(DateTimeFormatter.ISO_LOCAL_DATE);
    }

    /**
     * 获取一天的最大毫秒数
     *
     * @param time .
     * @return .
     */

    public static Long getDayStartMillis(Long time) {
        LocalDate localDate = asLocalDate(time);
        LocalDateTime localDateTime = localDate.atStartOfDay();
        return localDateTime.toInstant(ZoneOffset.ofHours(8))
                .toEpochMilli();
    }

    public static Long getDayEndMillis(Long time) {
        LocalDate localDate = asLocalDate(time);
        LocalDateTime localDateTime = localDate.atStartOfDay();
        LocalDateTime endTime = localDateTime.plusDays(1);
        return endTime.toInstant(ZoneOffset.ofHours(8))
                .toEpochMilli() - 1;
    }

    public static Long getMillis(LocalDateTime time) {
        return time.toInstant(ZoneOffset.ofHours(8))
                .toEpochMilli();
    }

    public static Long getMillis(String time) {
        return getMillis(LocalDateTime.parse(time, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
    }

    public static Long getMillis(String time, String format) {
        return getMillis(LocalDateTime.parse(time, DateTimeFormatter.ofPattern(format)));
    }

    @SneakyThrows
    public static List<String> getDateList(String start, String end) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        // 声明保存日期集合
        List<String> list = new ArrayList<>();
        // 转化成日期类型
        Date startDate = sdf.parse(start);
        Date endDate = sdf.parse(end);

        //用Calendar 进行日期比较判断
        Calendar calendar = Calendar.getInstance();
        while (startDate.getTime() <= endDate.getTime()) {
            // 把日期添加到集合
            list.add(sdf.format(startDate));
            // 设置日期
            calendar.setTime(startDate);
            //把日期增加一天
            calendar.add(Calendar.DATE, 1);
            // 获取增加后的日期
            startDate = calendar.getTime();
        }
        return list;
    }

    /**
     * 获取近n天的日期
     *
     * @param i 天数
     * @return .
     */
    public static List<String> getRecentDay(int i) {
        List<String> list = new ArrayList<>();
        for (int j = 0; j < i; j++) {
            list.add(formatToLocalDate(LocalDate.now()
                    .minusDays(j)));
        }
        return list;
    }

    /**
     * 获取前n天的日期
     *
     * @param i 天数
     * @return .
     */
    public static String getBeforeDay(int i) {
        return formatToLocalDate(LocalDate.now()
                .minusDays(i));
    }

    /**
     * 获取后n天的日期
     *
     * @param i 天数
     * @return .
     */
    public static String getAfterDay(int i) {
        return formatToLocalDate(LocalDate.now()
                .plusDays(i));
    }

    //根据传入的开始时间和结束时间，获取中间所有日期和星期数字，星期数字为1-7，1为星期一
    @SneakyThrows
    public static List<Map<String, String>> getBetweenDatesAndDayOfWeek(String beginDate, String endDate) {
        List<Map<String, String>> result = new ArrayList<>();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        Calendar tempStart = Calendar.getInstance();
        Calendar tempEnd = Calendar.getInstance();
        tempStart.setTime(sdf.parse(beginDate));
        tempEnd.setTime(sdf.parse(endDate));
        while (tempStart.getTimeInMillis() <= tempEnd.getTimeInMillis()) {
            Map<String, String> map = new HashMap<>();
            map.put("date", sdf.format(tempStart.getTime()));
            int i = tempStart.get(Calendar.DAY_OF_WEEK);
            if (i == 1) {
                i = 7;
            } else {
                i = i - 1;
            }
            map.put("dayOfWeek", String.valueOf(i));
            result.add(map);
            tempStart.add(Calendar.DAY_OF_YEAR, 1);
        }
        return result;
    }
}